package com.osi.mes.scan;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.comm.SerialPortEvent;
import javax.comm.SerialPortEventListener;
import com.datasweep.compatibility.client.Response;
import com.datasweep.compatibility.ui.ActivityControl;
import com.datasweep.compatibility.ui.SerialPort;
import com.datasweep.core.eventlog.EventLog;
import com.rockwell.activity.CComponentEvent;
import com.rockwell.activity.CComponentEventListener;
import com.rockwell.activity.ItemDescriptor;
import com.datasweep.compatibility.ui.ScriptArgument;


public class OSICOMActivity extends ActivityControl implements CComponentEventListener
{
	public static final String AFTER_SCANNED = "afterScanned";
	
	// custom event names
	public static final String[] customEvents = { AFTER_SCANNED };
	
	private boolean isAddComs = false;	

	// 扫描数据标记
	protected static Map<String, Boolean> waitForScanFlags = new HashMap<String, Boolean>();

	// 终止符标记
	static HashMap<String, Boolean> endMarkers = new HashMap<String, Boolean>();

	// 扫描超时时间 500毫秒
	static long SCAN_TIME_OUT = 500;

	// 超时标记
	static HashMap<String, Boolean> timeMarkers = new HashMap<String, Boolean>();

	/**
	 * 收到的条码 KEY为portName，VALUE为条码
	 */
	static Map<String, StringBuffer> receivedValue = new HashMap<String, StringBuffer>();

	/**
	 * COM设备集合
	 */
	private Map<String, OSISerialPort> comComponent = new HashMap<String, OSISerialPort>();

	private Map<String, String> barcodeMap = new HashMap<String, String>();
	
	public static final String RECEIVEDVALUE = "barcodeMap";
	
	public OSICOMActivity()
	{
		initUI();
	}

	/**
	 * 初始化界面
	 */
	private void initUI()
	{
		if (!isAddComs)
		{
			for (int i = 1; i <= 8; i++)
			{
				SerialPort serialPort = new SerialPort();
				serialPort.setName("COM" + i);
				serialPort.setActivityName("COM" + i);
				serialPort.setEnabled(false);
				add(serialPort);
			}
			isAddComs = true;
		}
		this.setVisible(false);
	}

	@Override
	public ItemDescriptor[] configurationDescriptors()
	{
		return null;
	}

	@Override
	public Response activityExecute()
	{
		return new Response();
	}

	@Override
	protected void configurationItemSet(String arg0, Object arg1)
	{

	}

	@Override
	protected void configurationLoaded()
	{

	}

	@Override
	public String getActivityDescription()
	{
		return "COM Reader";
	}

	@Override
	protected String[] getActivityEvents()
	{
		return customEvents;
	}

	@Override
	public ItemDescriptor[] inputDescriptors()
	{
		return null;
	}

	@Override
	protected void inputItemSet(String arg0, Object arg1)
	{

	}

	@Override
	public ItemDescriptor[] outputDescriptors()
	{
		return null;
	}
	
	@Override
	protected void shutdown()
	{

	}

	@Override
	protected void startup()
	{
		
	}

	@Override
	public Object ccomponentEventFired(CComponentEvent event)
	{
		return null;
	}

	/**
	 * 添加Com口监控
	 */
	private void addComs(String[] comNames)
	{
		for (int i = 0; i < comNames.length; i++)
		{
			addComComponent(comNames[i]);
		}
	}
	
	protected void addComComponent(String comName)
	{
		// 如果该COM组件已添加，则不需要再次添加
		if (comComponent.get(comName) != null)
		{
			return;
		}

		// System.out.println("初始化COM口："+comName);
		// 否则添加该COM组件
		SerialPort serialPort = (SerialPort) findActivityControl(comName);
		if (serialPort != null)
		{
			try
			{
				if (serialPort.getEnabled())
					serialPort.setEnabled(false);
				if (!serialPort.getPort().equals(
					comName))
					serialPort.setPort(comName);
				if (!serialPort.getEnabled())
					serialPort.setEnabled(true);
				comComponent.put(
					comName, new OSISerialPort(serialPort));
				receivedValue.put(
					comName, new StringBuffer());
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
	}

	/**
	 * COM监听器
	 * 
	 * @author Nemo
	 * 
	 */
	public class OSISerialPort
	{
		javax.comm.SerialPort mPort = null;

		boolean isAvaliable = false;

		public boolean isAvaliable()
		{
			return isAvaliable;
		}

		public void setAvaliable(boolean isAvaliable)
		{
			this.isAvaliable = isAvaliable;
		}

		public OSISerialPort(final SerialPort container)
		{
			if (container != null)
			{
				try
				{
					Class clazz = container.getClass();
					Field field = clazz.getDeclaredField("mPort");
					field.setAccessible(true);
					mPort = (javax.comm.SerialPort) field.get(container);
					if (mPort != null)
					{
						mPort.enableReceiveTimeout(100);
						mPort.removeEventListener();
						mPort.addEventListener(new SerialPortEventListener()
						{
							private final int CR = 13;

							private final int LF = 10;

							@Override
							public void serialEvent(SerialPortEvent event)
							{
								try
								{
									if (event.getSource().equals(
										mPort) && isAvaliable)
									{
										synchronized (receivedValue)
										{
											try
											{
												String portName = container.getPort();

												synchronized (waitForScanFlags)
												{
													// 若不存在该COMM口，添加该COMM口标记
													if (!waitForScanFlags.containsKey(portName))
													{
														waitForScanFlags.put(
															portName, true);
													}

													// 获得该COMM口标记
													Boolean waitForScanFlag = waitForScanFlags
														.get(portName);
													if (waitForScanFlag)
													{
														waitForScanFlags.put(
															portName, false);
														endMarkers.put(
															portName, false);
														timeMarkers.put(
															portName, false);

														ScanThread scanThread = new ScanThread(
															portName);
														scanThread.start();
													}

												}

												InputStream inputStream = mPort.getInputStream();
												int bytesAvailable = inputStream.available();
												if (bytesAvailable > 0)
												{
													byte[] input = new byte[bytesAvailable];
													inputStream.read(input);
													for (int i = 0; i < input.length; i++)
													{
														// 若遇到终止符，则直接返回数据
														if (input[i] == CR || input[i] == LF)
														{
															synchronized (endMarkers)
															{
																endMarkers.put(
																	portName, true);
															}
														}
														// 若没有遇到终止符
														else
														{
															receivedValue.get(
																portName).append(
																(char) input[i]);
														}
													}
												}
											}
											catch (IOException e)
											{
												EventLog.writeError("COM口加载失败: IOException is "
													+ e.getMessage());
											}
										}
									}
								}
								catch (Exception e)
								{
									EventLog.writeError("COM口加载失败: Exception is " + e.getMessage());
								}
							}
						});
						isAvaliable = true;
					}
				}
				catch (Exception e)
				{
					EventLog.writeError("COM口控件创建失败");
				}
			}
		}
	}

	class ScanThread extends Thread
	{

		String portName;

		long startTime = 0;

		ScanThread(String portName)
		{
			this.portName = portName;
		}

		@Override
		public void run()
		{
			String receiveValueStr = receivedValue.get(
				portName).toString();
			// 当数据存在时，开始计时
			if ((receiveValueStr != null && receiveValueStr.length() > 0) && (startTime == 0))
			{
				startTime = new Date().getTime();
			}
			// 等待扫描终止符或者超时500秒
			while (true)
			{
				// 当超时标记或终止符标记为真时，触发数据回收事件
				Boolean endMarker = false;
				synchronized (endMarkers)
				{
					endMarker = endMarkers.get(portName);
				}

				Boolean timeMarker = false;
				timeMarker = timeMarkers.get(portName);

				if (timeMarker || endMarker)
					break;
				else
				{
					long currentTime = new Date().getTime();
					long time = currentTime - startTime;
					if (SCAN_TIME_OUT < time)
					{
						timeMarkers.put(
							portName, true);
					}
				}
			}

			dataReceived(
				portName, receivedValue.get(
					portName).toString());

			// 扫描完成后，将标记回true，等待下次调用

			synchronized (waitForScanFlags)
			{
				waitForScanFlags.put(
					portName, true);
			}

			synchronized (receivedValue)
			{
				receivedValue.put(
					portName, new StringBuffer());
			}
			startTime = 0;
			synchronized (endMarkers)
			{
				endMarkers.put(
					portName, false);
			}

			synchronized (timeMarkers)
			{
				timeMarkers.put(
					portName, false);
			}
		}
	}

	/**
	 * Comm口收到数据后触发事件
	 */
	protected void dataReceived(String portName, String data)
	{
		barcodeMap.put(portName, data);
		ScriptArgument[] args = new ScriptArgument[1];
		args[0] = new ScriptArgument(RECEIVEDVALUE, barcodeMap);
		// evaluate the script
		fireActivityEvaluateScript(AFTER_SCANNED,args);
		barcodeMap.put(portName, null);
	}

	@Override
	protected void updateAfterExecute()
	{
		
	}
}
